package com.ssy.lingxi.contract.esign.api;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.Method;
import cn.hutool.json.JSONUtil;
import com.ssy.lingxi.contract.esign.constant.EsignConstants;
import com.ssy.lingxi.contract.esign.constant.RequestMethod;
import com.ssy.lingxi.contract.esign.exception.EsignError;
import com.ssy.lingxi.contract.esign.exception.EsignException;
import com.ssy.lingxi.contract.esign.response.EsignResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * API接口资源
 * @author yzc
 * @version 2.0.0
 * @date 2020/9/18
 */
@Slf4j
public class EsignResource {

    /**
     * 沙箱接口地址
     */
    private static final String TEST_URL = "https://smlopenapi.esign.cn";
    /**
     * 生产接口地址
     */
    private static final String PRO_URL = "https://openapi.esign.cn";


    public static String execute(EsignRequest esignRequest) throws EsignException {
        boolean debug = esignRequest.getProperties().isDebug();

        // 响应结果
        String result;

        // http请求后,参数被读取会置空, 克隆一个去请求
        result = executeRequest(esignRequest.getHttpMethod(), esignRequest.getResourcePath(), esignRequest.getHeaderMap(), ObjectUtils.clone(esignRequest.getParamMap()), esignRequest.getProperties().isSandBox());

        if (debug) {
            log.info("e签宝接口返回结果: {}", result);
        }

        if (!JSONUtil.isJson(result)) {
            throw new EsignException(EsignError.builder().errMsg("json格式异常").json(result).build());
        }

        // 序列化后响应结果
        EsignResponse esignResponse;
        esignResponse = JSONUtil.toBean(result, EsignResponse.class);

        // **这里可以换成最大重试去实现**
        // 未授权token错误
        if (EsignConstants.UNAUTHORIZED == esignResponse.getCode()) {
            // 重新获取token请求
            result = executeRequest(esignRequest.getHttpMethod(), esignRequest.getResourcePath(), esignRequest.getNewTokenHeaderMap(true), ObjectUtils.clone(esignRequest.getParamMap()), esignRequest.getProperties().isSandBox());
            esignResponse = JSONUtil.toBean(result, EsignResponse.class);

            // 未授权token错误
            if (EsignConstants.UNAUTHORIZED == esignResponse.getCode()) {
                result = executeRequest(esignRequest.getHttpMethod(), esignRequest.getResourcePath(), esignRequest.getNewTokenHeaderMap(true), ObjectUtils.clone(esignRequest.getParamMap()), esignRequest.getProperties().isSandBox());
                esignResponse = JSONUtil.toBean(result, EsignResponse.class);
            }
        }

        // 其他错误
        if (EsignConstants.SUCCESS != esignResponse.getCode()) {
            throw new EsignException(EsignError.builder().errCode(esignResponse.getCode()).errMsg(esignResponse.getMessage()).json(result).build());
        }

        return esignResponse.getData();
    }

    private static String formatUriResource(String resourcePath, Map<String, Object> paramMap) {
        if (Objects.isNull(resourcePath)) {
            return resourcePath;
        }

        Iterator<Map.Entry<String, Object>> iterator = paramMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Object> entry = iterator.next();
            String placeHolderName = "{" + entry.getKey().trim() + "}";
            if (resourcePath.contains(placeHolderName)) {
                if (Objects.isNull(entry.getValue())) {
                    continue;
                }
                // 替换uri的标识位
                resourcePath = resourcePath.replace(placeHolderName, entry.getValue().toString().trim());
                // 移除参数
                iterator.remove();
            }
        }

        return resourcePath;
    }

    private static String executeRequest(RequestMethod httpMethod, String resourcePath, Map<String, List<String>> headerMap, Map<String, Object> paramMap, boolean sandBox) throws EsignException {
        // 响应结果
        String result = "";
        if (RequestMethod.GET.equals(httpMethod)) {
            resourcePath = formatUriResource(resourcePath, paramMap);
            result = new HttpRequest(joinResourceUrl(sandBox, resourcePath)).method(Method.GET).header(headerMap).form(paramMap).execute().body();
        } else if (RequestMethod.DELETE.equals(httpMethod)) {
            resourcePath = formatUriResource(resourcePath, paramMap);
            result = new HttpRequest(joinResourceUrl(sandBox, resourcePath)).method(Method.DELETE).header(headerMap).form(paramMap).execute().body();
        } else if (RequestMethod.POST.equals(httpMethod)) {
            resourcePath = formatUriResource(resourcePath, paramMap);
            result = new HttpRequest(joinResourceUrl(sandBox, resourcePath)).method(Method.POST).header(headerMap).body(JSONUtil.toJsonStr(paramMap)).execute().body();
        } else if (RequestMethod.PUT.equals(httpMethod)) {
            resourcePath = formatUriResource(resourcePath, paramMap);
            result = new HttpRequest(joinResourceUrl(sandBox, resourcePath)).method(Method.PUT).header(headerMap).body(JSONUtil.toJsonStr(paramMap)).execute().body();
        }

        return result;
    }

    private static String joinResourceUrl(boolean sandBox, String resourcePath) {
        return (sandBox ? TEST_URL : PRO_URL) + resourcePath;
    }
}
